﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace LcfContols.DataBase.MySQL
{
    /// <summary>
    /// 对象表注解
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class LTable: Attribute
    {
        public string tablename = null;
    }

    /// <summary>
    /// 数据Bean主键注解类 ：作用是在生成insert语句时候忽略该字段
    /// </summary>
    [System.AttributeUsage(AttributeTargets.Property)]
    public class LDataItem : System.Attribute
    {
        /// <summary>
        /// 是否自增（自增在insert时候该值会被忽略）
        /// </summary>
        public bool autoKey = false;
        /// <summary>
        /// 是否不能为空
        /// </summary>
        public bool notNull = true;
        /// <summary>
        /// 默认值
        /// </summary>
        public object defultValue = null;
        /// <summary>
        /// 是否为主键（true=在更新是该值会被忽略）
        /// </summary>
        public bool primaryKey = false;

        /// <summary>
        /// 制定指定表字段名称。当该值为空时，字段名称为该注解所在字段的字段名
        /// </summary>
        public string item = null;
    }

    /// <summary>
    /// 自动生成SQL异常
    /// </summary>
    public class AutoSqlException:Exception
    {
        /// <summary>
        /// 错误消息
        /// </summary>
        /// <param name="msg"></param>
        public AutoSqlException(string msg) : base(msg) { }
    }

    /// <summary>
    /// 自动生成SQL语句
    /// </summary>
    public class AutoSql
    {

        /// <summary>
        /// 通过反射生成INSERT语句
        /// </summary>
        /// <param name="obj">对象bean</param>
        /// <param name="args">这是用来存放生成后sql条件参数的数组</param>
        /// <returns></returns>
        public static StringBuilder GetInsertString(object obj,out List<object> args)
        {
            args = new List<object>();
            StringBuilder sql = new StringBuilder("INSERT INTO ");
            StringBuilder sqlparams = new StringBuilder(" ) VALUES ( ");
            Type tp = obj.GetType();
            LTable datainfo = Attribute.GetCustomAttribute(tp, typeof(LTable)) as LTable;
            if (datainfo != null && !String.IsNullOrEmpty(datainfo.tablename))
            {
                sql.Append(datainfo.tablename).Append(" ( ");
                PropertyInfo[] propertys = tp.GetProperties();
                foreach (PropertyInfo p in propertys)
                {
                    LDataItem item = Attribute.GetCustomAttribute(p, typeof(LDataItem)) as LDataItem;
                    if (item != null)
                    {
                        object value = p.GetValue(obj,null);
                        string itemname = string.IsNullOrEmpty(item.item) ? p.Name : item.item;
                        if (!item.autoKey)
                        {
                            if (value != null)
                            {
                                sql.Append(itemname).Append(",");
                                sqlparams.Append("@" + p.Name).Append(",");
                                args.Add(value);
                            }
                            else if (item.notNull)
                            {
                                if (item.defultValue != null)
                                {
                                    sql.Append(itemname).Append(",");
                                    sqlparams.Append("@" + p.Name).Append(",");
                                    args.Add(item.defultValue);
                                }else{
                                    throw new AutoSqlException("字段：【" + p.Name + " 】不能为空 ");
                                }
                            }
                        }
                    }
                }
                sqlparams.Remove(sqlparams.Length - 1, 1);
                sql.Remove(sql.Length - 1, 1);
                sql.Append(sqlparams).Append(" )");
                return sql;
            }
            throw new AutoSqlException("类型:[" + tp.Name + "]未包含LTable注解，无法自动生成SQL");
        }

        /// <summary>
        /// 通过反射生成Update语句
        /// 注意：更新条件须自己后续增加。
        /// </summary>
        /// <param name="obj">对象bean</param>
        /// <param name="args">这是用来存放生成后sql条件参数的数组</param>
        /// <returns></returns>
        public static StringBuilder GetUpdateString(object obj, out List<object> args)
        {
            args = new List<object>();
            StringBuilder sql = new StringBuilder("UPDATE ");
            StringBuilder where = new StringBuilder(" WHERE ");
            Type tp = obj.GetType();
            LTable datainfo = Attribute.GetCustomAttribute(tp, typeof(LTable)) as LTable;
            if (datainfo != null && !String.IsNullOrEmpty(datainfo.tablename))
            {
                sql.Append(datainfo.tablename).Append(" SET ");
                PropertyInfo[] properties = tp.GetProperties();
                foreach (PropertyInfo p in properties)
                {
                    object value = p.GetValue(obj,null);
                    LDataItem item = Attribute.GetCustomAttribute(p, typeof(LDataItem)) as LDataItem;
                    string itemname = string.IsNullOrEmpty(item.item) ? p.Name : item.item;
                    if (!item.autoKey)
                    {
                        if (item.notNull && value == null)
                            return null;
                        sql.Append(" ").Append(itemname).Append(" = @").Append(p.Name).Append(",");
                        args.Add(value);
                    }
                }
                sql.Remove(sql.Length - 1, 1);
                return sql;
            }
            throw new AutoSqlException("类型:[" + tp.Name + "]未包含LTable注解，无法自动生成SQL");
        }
        
    }

}
